package cn.spikego.advicelite.client.core.event.impl

import cn.spikego.advicelite.client.core.event.util.EventCaller
import cn.spikego.advicelite.client.core.event.util.EventInitializer
import cn.spikego.advicelite.client.eventapi.events.Event
import cn.spikego.advicelite.client.mapping.MappingManager
import net.bytebuddy.ByteBuddy
import net.bytebuddy.asm.Advice
import net.bytebuddy.description.method.MethodDescription
import net.bytebuddy.dynamic.loading.ClassReloadingStrategy
import net.bytebuddy.dynamic.scaffold.TypeValidation
import net.bytebuddy.implementation.bind.annotation.RuntimeType
import net.bytebuddy.matcher.ElementMatcher

import net.bytebuddy.matcher.ElementMatchers.named
import net.bytebuddy.matcher.ElementMatchers.takesArgument

class KeyPressEvent() : Event, EventInitializer {

    var keyCode: Int = 0
    var pressType: Int = 0 // 1 = pressed, 0 = released, 2 = pressed still

    constructor(keyCode: Int, pressType: Int) : this() {
        this.keyCode = keyCode
        this.pressType = pressType
    }

    companion object {
        @JvmStatic
        @RuntimeType
        @Advice.OnMethodEnter(skipOn = Boolean::class)
        fun chat(
            @RuntimeType p_90894_: Long,
            p_90895_: Int,
            p_90896_: Int,
            p_90897_: Int,
            p_90898_: Int
        ): Boolean? {
            return if (EventCaller.callEvent("onKeyPress", p_90894_, p_90895_, p_90896_, p_90897_, p_90898_)) true else null
        }
    }

    @Throws(Exception::class)
    override fun initialize(byteBuddy: ByteBuddy, loader: ClassLoader, mappingManager: MappingManager) {
        val className = mappingManager.translateClassName("net.minecraft.client.KeyboardHandler")
        val methodName = mappingManager.translateMethodName("net.minecraft.client.KeyboardHandler", "keyPress(JIIII)V")
        val clazz = loader.loadClass(className)
        byteBuddy.with(TypeValidation.DISABLED)
            .redefine(clazz)
            .visit(
                Advice.to(Class.forName(this::class.java.name)).withExceptionPrinting()
                    .on(
                        ((named<MethodDescription>(methodName)
                            .and(takesArgument<MethodDescription>(0, java.lang.Long.TYPE))
                            .and(takesArgument<MethodDescription>(1, java.lang.Integer.TYPE))
                            .and(takesArgument<MethodDescription>(2, java.lang.Integer.TYPE))
                            .and(takesArgument<MethodDescription>(3, java.lang.Integer.TYPE))
                            .and(takesArgument<MethodDescription>(4, java.lang.Integer.TYPE)))
                                as ElementMatcher<in MethodDescription>)
                    )
            )
            .make().load(loader, ClassReloadingStrategy.fromInstalledAgent())
    }
}